/*
** pud_mem.c for pud in mrcellophane/libpud
** 
** Made by solomon hykes
** Login   <torgau@gmail.com>
** 
** Started on  Mon May 16 19:10:54 2005 solomon hykes
** Last update Wed May 18 17:23:49 2005 solomon hykes
*/

#include "pud_sys.h"

static inline t_ret	p_read(int pid, u_long addr, u_long *where)
{
  while (1)
    {
      errno = 0;
      *where = ptrace(PT_READ_D, pid, (caddr_t)addr, 0);
      if (!errno)
	return (ret_ok);
      if (errno != EAGAIN)
	return (ret_err);
    }
}

static inline t_ret	p_write(int pid, u_long addr, u_long what)
{
  while (ptrace(PT_WRITE_D, pid, (caddr_t)addr, what) == -1)
    if (errno != EAGAIN)
      return (ret_err);
  return (ret_ok);
}

/* Memory  */

size_t		pud_mem_read(pud_process *p, u_long addr, char *buf, size_t len)
{
  sys_pud_process	*proc = (sys_pud_process *)p;
  u_long		*word;
  int			pos;
  size_t		trunc_len;

  if (len < sizeof(long))
    {
      u_long	l;
      
      if (p_read(proc->pid, addr, &l) == ret_err)
	return (-1);
      for (pos = 0; pos < len; pos++)
	buf[pos] = ((char *)&l)[pos];
      return (len);
    }
  trunc_len = len - (len % sizeof(long));
  word = (u_long *)buf;
  for (pos = 0; pos < trunc_len; pos += sizeof(long))
    {
      if (p_read(proc->pid, addr + pos, word) == ret_err)
	return (-1);
      word++;
    }
  if (len != trunc_len)
    {
	{
	  word = (u_long *)(buf + len - sizeof(long));
	  if (p_read(proc->pid, addr + len - sizeof(long), word) == ret_err)
	    return (-1);
	}
    }
  return (len);
}


size_t		pud_mem_write(pud_process *p, u_long addr, char *buf, size_t len)
{
  sys_pud_process	*proc = (sys_pud_process *)p;
  u_long		*word;
  int			pos;
  size_t		trunc_len;

  if (len < sizeof(long))
    {
      u_long	l;

      if (p_read(proc->pid, addr, &l) == ret_err)
	return (-1);
      for (pos = 0; pos < len; pos++)
	((char *)&l)[pos] = buf[pos];
      if (p_write(proc->pid, addr, l) == ret_err)
	return (-1);
      return (len);
    }
  trunc_len = len - (len % sizeof(long));
  word = (u_long *)buf;
  for (pos = 0; pos < trunc_len; pos += sizeof(long))
    {
      if (p_write(proc->pid, addr + pos, *word) == ret_err)
	return (-1);
      word++;
    }
  if (len != trunc_len)
    {
      word = (u_long *)(buf + len - sizeof(long));
      if (p_write(proc->pid, addr + len - sizeof(long), *word) == ret_err)
	return (-1);
    }
  return (len);
}
